/*
 *  Copyright (C) 2010 Glauco
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.balisunrise.annotation.util;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import org.balisunrise.annotation.Create;
import org.balisunrise.annotation.VisualEntity;
import org.balisunrise.annotation.Transaction;

/**
 * Esta classe contém os atributos para construção de uma transação para uma
 * entidade.
 * @author Glauco
 */
public class TransactionUtilities extends VisualEntityUtilities{

    private static final String MESSAGE = "Erro ao ler Annotation \"Transaction\".";

    /**
     * Alias (nome) do editor.
     */
    public String editor;

    /**
     * Alias (nome) da busca.
     */
    public String search;

    /**
     * EditorUtilities construído com o alias editor.
     */
    public EditorUtilities editorUtilities;

    /**
     * SearchUtilities construído com o alias search.
     */
    public SearchUtilities searchUtilities;

    /**
     * Metodo para criação de novas instâncias.
     */
    public Method createMethod;

    /**
     * Lê a annotation Transaction com o alias da VisualEntity.
     * @param entityClass Classe para ler.
     * @param alias alias da Transaction.
     * @return a annotation Transaction do alias.
     * @throws AnnotationsUtilitiesException Caso não encontre.
     */
    public static Transaction readTransactionAnnotation(
            Class entityClass, String alias)
            throws AnnotationsUtilitiesException {

        if (entityClass == null)
            throw new AnnotationsUtilitiesException( MESSAGE +
                    "\nParâmentro \"entityClass\" não pode ser nulo!");

        if (alias == null)
            throw new AnnotationsUtilitiesException( MESSAGE +
                    "\nParâmentro \"alias\" não pode ser nulo!");

        VisualEntity ve = readVisualEntityAnnotation(entityClass);
        for (Transaction t : ve.transactions()) {
            if(t.alias().equals(alias)){
                return t;
            }
        }

        throw new AnnotationsUtilitiesException( MESSAGE +
                "\nAnnotation \"Transaction\" não encontrada para o "
                + "nome \""+ alias +"\"!");

    }

    /**
     * Le a annotation Transaction e cria um TransactionUtilities a parir dos
     * dados da annotation.
     *
     * @param entityClass Classe para ler.
     * @param alias alias da Transaction.
     * @return TransactionUtilities
     * @throws AnnotationsUtilitiesException Caso não encontre a annotation ou
     * algum parâmetro seja nulo.
     */
    public static TransactionUtilities create(Class entityClass, String alias)
            throws AnnotationsUtilitiesException {

        if (entityClass == null)
            throw new AnnotationsUtilitiesException( MESSAGE +
                    "\nParâmentro \"entityClass\" não pode ser nulo!");

        if (alias == null)
            throw new AnnotationsUtilitiesException( MESSAGE +
                    "\nParâmentro \"alias\" não pode ser nulo!");
        
        Transaction t = readTransactionAnnotation(entityClass, alias);

        TransactionUtilities tu = new TransactionUtilities();
        tu.entityClass = entityClass;
        tu.alias = alias;
        tu.title = t.title();
        tu.editor = t.editor();
        tu.search = t.search();

        // constrói Editor
        tu.editorUtilities = EditorUtilities.create(entityClass, tu.editor);
        
        // constrói Search
        tu.searchUtilities = SearchUtilities.create(entityClass, tu.search);

        // metodo para criação de uma nova instância
        tu.createMethod = getCreateMethod(entityClass, alias);

        return tu;

    }

    /**
     * Busca por um método para criar uma nova instância.
     * O Método deve conter a anotação @code(Create), retornar uma objeto da
     * classe da entidade, ser public e não possuir parâmetros.
     * é verificado o alias recebido por parâmetro com os alias da anotação.
     *
     * @param entityClass classe da entidade com o método.
     * @param alias alias para comparar.
     * @return Method para criar uma nova instância, ou nulo caso não encontre
     * nenhum.
     * @throws AnnotationsUtilitiesException caso algum parâmetro seja nulo.
     * @see org.balisunrise.annotation.Create
     */
    public static Method getCreateMethod(
            Class entityClass, String alias)
            throws AnnotationsUtilitiesException {

        if (entityClass == null)
            throw new AnnotationsUtilitiesException( MESSAGE +
                    "\nParâmentro \"entityClass\" não pode ser nulo!");

        if (alias == null)
            throw new AnnotationsUtilitiesException( MESSAGE +
                    "\nParâmentro \"alias\" não pode ser nulo!");

        for (Method m : entityClass.getDeclaredMethods()) {
            if (m.isAnnotationPresent(Create.class)){
                Create create = m.getAnnotation(Create.class);
                for (String cAlias : create.alias()) {
                    if(cAlias.equals(alias))
                        if(m.getParameterTypes().length == 0 &&
                                m.getReturnType().equals(entityClass) &&
                                Modifier.isPublic(m.getModifiers()) &&
                                Modifier.isStatic(m.getModifiers()))
                            return m;
                }
            }
        }

        return null;
    }
}
